package com.lxy.exportword.util;

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.style.PictureStyle;
import com.lxy.exportword.annotation.TablePicture;
import com.lxy.exportword.constant.WordConstant;
import com.lxy.exportword.entity.base.BaseEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * word工具类
 * Poi-tl模板引擎官方文档：http://deepoove.com/poi-tl/
 * @author LiuXiaoYu ZhangLiXiang
 */
@Slf4j
public class WordUtil {

    /**
     * 根据模板填充内容生成word，并下载
     */
    public static void downloadWord(HttpServletResponse response, XWPFTemplate template) {

        ServletOutputStream outputStream;
        try {
        	//out = new FileOutputStream(filePath);//输出路径(下载到指定路径)
            // 将填充之后的模板写入filePath
            outputStream=response.getOutputStream();
            //将template写到OutputStream中
            template.write(outputStream);
        	outputStream.flush();
        	outputStream.close();
        	template.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 计算合计值
     * @return
     */
    public static BigDecimal getTotal(List<? extends BaseEntity> list) {
        BigDecimal total=new BigDecimal("0");
        List<String> collect = list.stream().map(BaseEntity::getKilometers).collect(Collectors.toList());
        for (String s : collect) {
            if (Objects.nonNull(s)&&!StringUtils.isEmpty(s)&&s.contains(WordConstant.CHINESE_LEFT_BRACKET)){
                //说明是合计只要有左括号就是要乘起来的那种
                s=s.replaceAll("（", "").replaceAll("）","");
                String[] split=s.split("\\*");
                BigDecimal per = new BigDecimal(split[0]);
                BigDecimal count = new BigDecimal(split[1]);
                BigDecimal totalPer = per.multiply(count);
                total=total.add(totalPer);
            }else if (Objects.nonNull(s)&&!StringUtils.isEmpty(s)){
                //没有括号就不用乘数量直接加起来
                BigDecimal bigDecimal=new BigDecimal(s);
                total=total.add(bigDecimal);
            }
        }
        return total;
    }

    /**
     * 通过一个类的对象实例的Class对象得到这个类本身
     * @return
     */
    public static<T> Map<String, Object> getAllFieldNameAndValueToMap(Object target) throws IntrospectionException {
        Map<String,Object> map=new HashMap<>();
        //得到这个对象实例的Class对象
        Class<?> clazz = target.getClass();
        //得到这个对象的类所有的属性
        Field[] tableFields = clazz.getDeclaredFields();
        //得到这个这个对象的类的父类的Class对象
        Class<?> superClazz = clazz.getSuperclass();
        //得到这个对象的类的父类所有的属性
        Field[] tableSuperFields = superClazz.getDeclaredFields();
        //然后合成一个大的Fields对象
        Field[] superFields = new Field[tableFields.length + tableSuperFields.length];
        System.arraycopy(tableFields, 0, superFields, 0, tableFields.length);
        System.arraycopy(tableSuperFields, 0, superFields, tableFields.length, tableSuperFields.length);
        //递归得到这个类本身属性以及除了object的所有父类属性
        Field[] allFields = getSuperClassFields(superFields, superClazz);
        getAllFieldNameAndValue(target,map,allFields,clazz);

        return map;
    }

    /**
     * 抽取公共部分
     * @param map map集合
     * @param allFields 所有属性
     */
    private static void getAllFieldNameAndValue(Object target,Map<String, Object> map, Field[] allFields, Class<?> clazz) throws IntrospectionException {
        for (Field allField : allFields) {
            //得到属性名称
            String name = allField.getName();
            PropertyDescriptor pd = new PropertyDescriptor(name, clazz);
            //获得get方法
            Method getMethod = pd.getReadMethod();
            //得到属性值
            Object fieldValue = org.springframework.util.ReflectionUtils.invokeMethod(getMethod, target);
            if (Objects.isNull(fieldValue)) {
                //若属性值为空则跳过此次循环
                continue;
            }
            TablePicture annotation = allField.getAnnotation(TablePicture.class);
            if (Objects.nonNull(annotation)){
                if (allField.getGenericType().getTypeName().contains("PictureRenderData")){
                   //说明是图片属性 即使是一张图片也用List集合包裹 如果需要多张时也方便
                    //得到该图片要设置的高度
                    int height = annotation.height();
                    //得到该图片要设置的宽度
                    int width=annotation.width();
                    //然后将属性类型转为List<Map<String,PictureRenderData>>
                    List<Map<String, PictureRenderData>> pictureRenderList= (List<Map<String, PictureRenderData>>) fieldValue;
                    //遍历
                    List<Map<String, PictureRenderData>> newPictureRenderList = pictureRenderList.stream().peek(pictureRenderDataMap -> pictureRenderDataMap.forEach((key, value) -> {
                        PictureStyle pictureStyle = new PictureStyle();
                        pictureStyle.setWidth(width);
                        pictureStyle.setHeight(height);
                        value.setPictureStyle(pictureStyle);
                    })).collect(Collectors.toList());
                    map.put(name,newPictureRenderList);
                }else {
                    //说明虽然加了注解但根本不是图片属性 但影响不大给出警告即可
                    log.warn(target.getClass().getName()+"中的"+name+"图片大小注解需要加在图片属性上");
                }
            }else {
                //说明是图片属性忘加图片大小注解了,给出警告
                if (allField.getGenericType().getTypeName().contains("PictureRenderData")){
                    //日志提示
                    log.warn(target.getClass().getName()+"中的"+name+"集合属性好像忘记加图片大小注解了,图片会很大哦");
                }
                map.put(name,fieldValue);
            }
        }
    }

    /**
     * 只得到这个对象本身的所有属性名及属性值
     * @param target 目标对象
     * @return Map集合
     * @throws IntrospectionException 反射异常
     */
    public static Map<String,Object> getOnlySelfFieldNameAndValue(Object target) throws IntrospectionException {
        Map<String,Object> map=new HashMap<>();
        Class<?> clazz = target.getClass();
        Field[] tableFields = clazz.getDeclaredFields();
        getAllFieldNameAndValue(target,map,tableFields,clazz);
        return map;
    }

    /**
     * 递归获取某个类及其所有父类的所有字段
     * @param tableFields
     * @param clazz
     * @return
     */
    private static Field[] getSuperClassFields(Field[] tableFields, Class<?> clazz) {
        Class<?> superClazz = clazz.getSuperclass();
        if (superClazz.equals(Object.class)) {
            return tableFields;
        }
        Field[] tableSuperFields = superClazz.getDeclaredFields();

        Field[] c = new Field[tableFields.length + tableSuperFields.length];
        System.arraycopy(tableFields, 0, c, 0, tableFields.length);
        System.arraycopy(tableSuperFields, 0, c, tableFields.length, tableSuperFields.length);
        getSuperClassFields(c, superClazz);
        return c;
    }
}